home *** CD-ROM | disk | FTP | other *** search
/ CD ROM Paradise Collection 4 / CD ROM Paradise Collection 4 1995 Nov.iso / system / xpcmou10.zip / xpcmouse.asm < prev    next >
Assembly Source File  |  1994-12-16  |  76KB  |  2,349 lines

  1.  
  2. comment *
  3.  
  4.   XPC-Mouse:  POSITION CURSOR, COPY and PASTE in Dos Text Mode
  5.  
  6.   Copyright (c) 1994 by Jürgen G. Weber and Grant B. Gustafson.
  7.   ALL RIGHTS RESERVED
  8.  
  9.   Free for personal use under the Gnu Public License agreement, which is
  10.   distributed with this source. See the end of this file for a copy of
  11.   the License Agreement.
  12.  
  13.   CREDITS
  14.   ----------------------------------------------------------------------
  15.   Portions of this code originated with and were extracted from
  16.   PCMOUSE  (c) 1992,1994 by  Jürgen G. Weber
  17.                              Wiesentalstraße 1
  18.                              D-74523 Schwäbisch Hall
  19.                              Germany - European Union
  20.  
  21.   This ASM source written by GB Gustafson
  22.                              113 JWB Math Dept Univ Utah
  23.                              Salt Lake City, UT 84112
  24.                              USA
  25.   in collaboration with Jürgen G. Weber to create this new product.
  26.   Portions of this ASM code also appeared in MOUSE2G, copyright (c)
  27.   1991, 1992 by GB Gustafson. Finally, credits are due to Al Williams,
  28.   for solid advice about TSR's, in his book "DOS 5: A Developers Guide",
  29.   M&T Press, 1991, and to Dave Williams, for his electronic reference on
  30.   DOS, especially the mouse information and interrupt details.
  31.   ----------------------------------------------------------------------
  32.  
  33.   XPC-Mouse
  34.   POSITION CURSOR, COPY and PASTE in Dos Text Mode
  35.  
  36.   Function: Highlight text while left button is pressed. Left release
  37.             causes the selected text to be copied from the screen into
  38.             an internal pastebuffer. The right button (i.e., button2)
  39.             pastes the pastebuffer at the text cursor position. Left
  40.             button press of 1/6 second positions the text cursor
  41.             [defeatable]. Emacs/vi, matrix and Xterm style mouse action
  42.             methods. See the HELP at the end of the file for more.
  43.  
  44.   MAKE:     tasm xpcmouse
  45.             tlink xpcmouse
  46.  
  47.   COMMAND LINE OPTIONS: /U /T /Q /N /R /Xddd /Bddd /M /K /P /A1 /A2 /A3 /C /H
  48.                         See help text at the end of the file.
  49.   STARTUP DEFAULTS:
  50.             Auto default for video XOR highlight mask
  51.                /X80 for color modes (xor mask == 64+16 )
  52.                /M for mono modes (/M==/X119, xor mask == 64+32+16+4+2+1)
  53.             /A1 for Emacs/jed/vi arrow keys
  54.             /U, /Q, /N, /R, /T, /C, /?, /A2, /A3 defeated
  55.             /K and /P toggles are ON
  56.             /B128 is the default paste buffer size (16)(128)==2048 bytes
  57.  
  58.   VERSIONS:
  59.   1.0  First public release.
  60.  
  61.   Features of 1.0 inherited from Jürgen G. Weber's PC-Mouse versions 1.0-1.5:
  62.           Option /T, enable stuffing the paste buffer into the
  63.             keyboard buffer at every timer (int 1ch) tick.
  64.           Un-install Option /U. Mouse hardware reset after de-install.
  65.           8088 Version. Support mono, color, ega, vga text modes.
  66.           Option /Xddd for XOR mask
  67.           Option /Q for quiet start up
  68.           Option /N to defeat int 21h patch.
  69.           Option /R to reactivate TSR.
  70.           Pastebuffer compression and interrupt logic.
  71.           Install and de-install routines.
  72.  
  73.   Features of 1.0 originating with this ASM source written by GB Gustafson:
  74.           Pressing the left button for 1/6 second positions the cursor.
  75.           Default /A1 for emacs/vi/jove/jed/epsilon mouse action.
  76.           Option /A2 is matrix mouse action, qedit/pi editors.
  77.           Option /A3 is for Xterm X10/X11 style escapes \033[M cb cx cy.
  78.             Works with remote jed/emacs/pi and extensible editors.
  79.           Toggle /A state dynamically using SHIFT-ALT-button1
  80.             with ring selection /A1 --> /A2 --> /A3 --> /A1.
  81.           Option /K defeats arrow keys and Xterm sequences.
  82.           Option /P defeats the pastebuffer.
  83.           ALT-button2 duplicates button3 (for 2-button mouse).
  84.           SHIFT-button1 toggles arrow keys on/off (see /K).
  85.           SHIFT-button2 toggles the pastebuffer on/off (see /P).
  86.           Option /M for monochrome Video mode (/M==/X119).
  87.           Unix file name selection on double-click using the idea
  88.             of the X11R5 Xterm character classes.
  89.           Hide mouse cursor after highlighting.
  90.           Auto default for video XOR highlight mask
  91.                /X80 for color modes (xor mask == 64+16 )
  92.                /M for mono modes (/M==/X119, xor mask == 64+32+16+4+2+1)
  93.           Help file dump /? gives switch information.
  94.           Author, copying and copyright switch /C for shorter signon.
  95.           Help file dump /H gives How-To information on mouse actions.
  96.           Dynamic buffer size up to max size compiled into program.
  97.           GNU license agreement.
  98.  
  99.  Bug fixes:
  100.           /T was always ON. Reset to initially OFF. 1-Dec-94
  101.  
  102.           /T ASM code caused characters to be lost on paste, traced to
  103.           recursive call of interrupt 1ch. Fixed by setting a flag to
  104.           bypass the second call (until the first one finished). This
  105.           bug was also in PCMOUSE 1.5, as observed under SunPC and sun4
  106.           OS.
  107.  
  108.           /T off worked with paste, but not with arrow keys. Traced to
  109.           convoluted code which bypassed a call to stuff the keybuffer.
  110.           Fixed by having a central place where the mouse handler calls
  111.           the stuffer routines (near the exit).
  112.  
  113.  TESTING:
  114.  The TSR was tested on about 5 different PC machines dating from 1984 to
  115.  1993 manufacture. CPU's tested: 80286, 80386SX, 80386DX, 80486SX,
  116.  80486DX. No workable XT 8088 could be found for testing! However, an XT
  117.  style non-extended keyboard was used and found to work.
  118.  
  119.  Not tested with XT turned off in the ASM code. It will probably not
  120.  affect the TSR to do so, but the code as now written does not make use
  121.  of 80286+ opcodes or special features of int 16h. Some mouse drivers
  122.  and BIOS combinations disable the TSR unless it is compiled with the
  123.  8088 code control symbol "XT", because the nonresident CPU and mouse
  124.  BIOS tests cause the TSR to fail it's initial load. However, the
  125.  failure is superficial: it may only affect de-install /U on most
  126.  machines.
  127.  
  128.  Loads high with devices "HIMEM.SYS" and "EMM386.EXE noems" /w control
  129.  "DOS=HIGH,UMB" under DOS 5.0 and 6.2. Loaded low with 386max, did not
  130.  test loaded into high umb's under 386max.
  131.  
  132.  Works with DOS 4.01 under SoftPC version 3 (1992) for SUN4 OS (SunPC,
  133.  DOS emulator from Sun Microsystems, standard configuration). This is
  134.  the only mouse TSR known to work for DOS copy/paste/position in a unix
  135.  environment (X-windows, DOS emulator). Used with COMMANDO TSR, no
  136.  conflicts loaded low. Also works with WCED loaded high or low. In both,
  137.  the arrow key feature allows positioning on the command line.
  138.  
  139.  MEMORY USAGE:
  140.  Complaints about the TSR's resident size should take note that it will
  141.  reside in high memory and eat about 4.6k. By cutting out the
  142.  pastebuffer, using option "/B0 /P", usage can be reduced to 2.6k. A
  143.  recompile, removing the arrow key code or the pastebuffer code will
  144.  cause correspondingly significant code size reductions. Resident code
  145.  size below 2.2k is possible, without paste buffer features.
  146.  
  147.  EDITORS TESTED:
  148.  Remote over modem line: Emacs, vi, jed, jove, pi.
  149.  Local PC: epsilon, pi, qedit.
  150.  
  151.  Special interfaces tested: emacs, jed, pi.
  152.    For these, we had to write extension code for the editor involved, or
  153.    else modify the sources. The standard "mousex.sl" in the JED library
  154.    works as written. PI needed the unix Xterm mouse code enabled for
  155.    compilation under DOS. EMACS needed a special LISP function for the
  156.    mouse motions.
  157.  
  158. * ; End comment
  159.  
  160. PVERSION equ '1.0: 3 Dec 1994'
  161.  
  162. TRUE equ -1
  163. FALSE equ not TRUE
  164. ;
  165. ; Compile Time switches that change the final EXE size.
  166. ; EXE size is most affected by BUFFERLEN value. The
  167. ; actual resident code is about 2.25k total (help text not resident).
  168. ; The paste buffer is variable, size 0 to BUFFERLEN, and this adds
  169. ; up to 2k to the resident code size.
  170. ;
  171. XT equ TRUE             ; TRUE for PC or XT 8086/8088 cpu and old bios.
  172.                         ; FALSE for 80188+ cpu, new bios and 286 opcodes.
  173.  
  174. BUFFERLEN EQU 2048      ; Max buffer size for copying text and attributes.
  175.                         ; Enough for a full screen. Blanks are compressed.
  176.                         ; 1024 is enough for 1/2 of screen. Use /Bddd
  177.                         ; option to set runtime buffer size (can be zero).
  178.                         ; Code actually uses "BUFLEN" variable.
  179. ;
  180. ; Masks for mouse events
  181. ;
  182. M_MOVED       EQU 1B       ;bit 0   mouse movement
  183. M_LT_PRESSED  EQU 10B      ;bit 1   left button pressed
  184. M_LT_RELEASED EQU 100B     ;bit 2   left button released
  185. M_RT_PRESSED  EQU 1000B    ;bit 3   right button pressed
  186. M_RT_RELEASED EQU 10000B   ;bit 4   right button released
  187. M_MI_PRESSED  EQU 100000B  ;bit 5   middle button pressed (Mouse Systems)
  188. M_MI_RELEASED EQU 1000000B ;bit 6   middle button released (Mouse Systems)
  189.  
  190. SPEED_LDC equ 9       ; Double click threshold 9/18.2 seconds
  191. ;
  192.  
  193. if not XT
  194.  .286  ; the times, they're a-changing ...  memento mori 808[6|8]
  195. endif
  196.  
  197. locals                  ; makes the local @@Label possible
  198.  
  199. ; Useful macros
  200. ;
  201. PUSHR macro regs   ;; eg: PUSHR <bx,ax,cx>
  202. local reg
  203.    irp reg,<regs>
  204.      push reg
  205.    endm
  206. endm
  207.  
  208. POPR  macro regs   ;; eg: POPR  <cx,ax,bx>
  209. local reg
  210.    irp reg,<regs>
  211.      pop  reg
  212.    endm
  213. endm
  214.  
  215.  XPUSHA macro
  216. if XT
  217.         PUSHR <AX,BX,CX,DX,BP,SI,DI>
  218. else
  219.         pusha
  220. endif
  221.  endm
  222.  
  223.  XPOPA macro
  224. if XT
  225.         POPR <DI,SI,BP,DX,CX,BX,AX>
  226. else
  227.         popa
  228. endif
  229.  endm
  230.  
  231. code segment
  232. assume cs:code
  233.  
  234. begin_resident equ $    ; All resident code starts here
  235.  
  236. flag_int21 db FALSE          ; TRUE if int 21h is patched.
  237. flag_int1c db FALSE          ; TRUE to stuff keybuffer at timer ticks.
  238. counter_int10 dw 0           ; Incremented at each call of int 10h
  239. flag_Left db FALSE           ; TRUE if left button was pressed.
  240. flag_Right db FALSE          ; TRUE when right button pressed.
  241. flag_Highlight db FALSE      ; TRUE if an area is highlighted on screen.
  242. flag_MouseOn db FALSE        ; TRUE if mouse cursor is on.
  243. flag_CtrlRight db FALSE      ; TRUE if last click was ctrl-right
  244. old_mousemask dw 0           ; Mask used by last mouse handler.
  245. old_mouseAddr dw 0,0         ; Far address of last mouse handler.
  246. PositionLeft dw 0            ; Position of mouse at left click
  247. NextPositionLeft dw 0        ; Position of mouse at a later left click
  248. xor_mask db 01010000b        ; XOR mask for selected screen area
  249. xor_pointer dw 0             ; Pointer to screen area to be xor'ed
  250. lastChar db 0                ; Saved character from failed key-stuff.
  251. lineSize dw 0                ; Characters per line on screen
  252. videosegment  dw 0           ; Segment of screen memory
  253. videoOffset dw 0             ; Offset into video page
  254. lasttime dw 0,0              ; System time at last left click
  255. counter_blanks db 0          ; Counter for blanks yet to be stuffed.
  256. nextpair dw offset pastebuf  ; Pointer to next character pair in paste buffer.
  257. lastpair dw offset pastebuf  ; Pointer to end of text in paste buffer.
  258.  
  259. flag_arrowkeys   db 1        ; Arrowkeys initially ON
  260. flag_pastebuffer db 1        ; Pastebuffer initially ON
  261. flag_editor  db 1            ; 1=emacs/vi/jove/jed, 2=matrix, 3=Xterm,
  262. flag_double  db FALSE        ; TRUE if left button was double-clicked
  263. flag_busy_stuffing db 0      ; TRUE if stuffing keys (see new int 1ch)
  264. flag_doButton13 db FALSE     ; TRUE if we are to send button1 + button3
  265. flag_doButton2  db FALSE     ; TRUE if we are to send button2
  266. flag_doButton3  db FALSE     ; TRUE if we are to send button3
  267. current_X        dw 0        ; Current mouse X coordinate (transient)
  268. current_Y        dw 0        ; Current mouse Y coordinate (transient)
  269. EndOfBuffer dw pastebuf+BUFFERLEN-1     ; Address of end of paste buffer
  270. MAX_of_A equ 4               ; max number of /A options (1,2,3) plus 1
  271.  
  272. SPEED_LC     equ 3      ; About 3/18.2 sec left button press required.
  273. col_present  db 0       ; col for text cursor (not mouse cursor!)
  274. row_present  db 0       ; row for text cursor
  275. col_target   db 0       ; col where left button was pressed
  276. row_target   db 0       ; row where left button was pressed
  277.  
  278. ; Xterm escapes for buttons 1,2,3 are in format ASCII,SCANCODE
  279. ; because they are to be stuffed directly into the keybuffer.
  280. ;
  281. ; Escape sequence for button 1
  282. Button1_ESC db 1bh, 01h ; ESC
  283.             db '[',1ah  ; [
  284.             db 'M',32h  ; M
  285.             db 20h,39h  ; SPACE
  286. Button1_COL db 00h,00h  ; Column position
  287.             db 00h,00h  ; Row position
  288. Button1_LEN equ 6       ; Number of pairs in sequence
  289. ; Escape sequence for button 2
  290. Button2_ESC db 1bh, 01h ; ESC
  291.             db '[',1ah  ; [
  292.             db 'M',32h  ; M
  293.             db 21h,02h  ; SPACE+1
  294. Button2_COL db 00h,00h  ; Column position
  295.             db 00h,00h  ; Row position
  296. Button2_LEN equ 6       ; Number of pairs in sequence
  297. ; Escape sequence for button 3
  298. Button3_ESC db 1bh, 01h ; ESC
  299.             db '[',1ah  ; [
  300.             db 'M',32h  ; M
  301.             db 22h,28h  ; SPACE+2
  302. Button3_COL db 00h,00h  ; Column position
  303.             db 00h,00h  ; Row position
  304. Button3_LEN equ 6       ; Number of pairs in sequence
  305. ;
  306. Xterm_PAD equ ' '+1     ; Offset for Xterm escapes row,col
  307. ;
  308.  
  309. ; Xterm-style char classes for double-click
  310. ; Inequality a<=x<=b coded as "db a,b" below.
  311. ;
  312. unix_pairs db 9         ; Number of active pairs below
  313. unix_ranges db 35,35    ; # (pound)
  314.             db 45,57    ; -./0123456789
  315.             db 64,90    ; @ABCDEFGHIJKLMNOPQRSTUVWXYZ
  316.             db 92,92    ; \ (backslash)
  317.             db 95,95    ; _ (underline)
  318.             db 97,122   ; abcdefghijklmnopqrstuvwxyz
  319.             db 126,126  ; ~ (tilde)
  320.             db 128,165  ; European letters
  321.             db 224,238  ; Greek letters and infinity
  322.             db 0,0      ; extra space for more combos
  323.             db 0,0      ; This table can be changed dynamically
  324.             db 0,0      ; on program load or restart (not implemented).
  325.             db 0,0      ; If you change this, also change
  326.             db 0,0      ; variable "unix_pairs" above!
  327.  
  328. ;
  329. ; The MOUSE HANDLER is called by the mouse driver
  330. ; if an event occurs which matches the CX mask
  331. ; that was supplied at the time of installation.
  332. ; ENTRY:  The mouse device driver supplies this info:
  333. ; AX=Mouse event bits
  334. ; BX=button state: bit0=left, bit1=right, bit2=center
  335. ; CX=current X coordinate, DX=current Y coordinate
  336. ; SI=raw Y mickeys, DI=raw X mickeys
  337. ; DS=driver's data segment
  338. ;
  339. MouseHandler proc far        ; Handler ends with far ret
  340.       XPUSHA                 ; handler can't modify registers
  341.       push ds                ; can't call DOS or BIOS
  342. ;
  343. ; Do not let mouse routines happen if interrupt 10h is active
  344. ; or is there is no text mode active (eg, graphics modes ==> no mouse)
  345. ;
  346.       cmp counter_int10,0    ; Int 10h interrupted?
  347.         jne short @@exit1    ; Yes, then get out of here.
  348.  
  349. @@not_in10:
  350.       mov current_X,cx       ; Save button X and Y coordinates
  351.       mov current_Y,dx       ; from this call.
  352.  
  353.       push ax
  354.       mov ax,40h             ; bios data area segment address
  355.       mov ds,ax              ; Use DS to read bios variables.
  356.       pop ax
  357.       cmp byte ptr [ds:49h],3  ; BIOS current video mode
  358.         jna short @@test_events
  359.       cmp byte ptr [ds:49h],7  ; BIOS current video mode
  360.         jz  short @@test_events
  361.       cmp byte ptr [ds:49h],13h ; Other video modes are graphics
  362.         jna short @@exit1
  363.      cmp word ptr [ds:4ch],0800h ; Assume text mode if video memory
  364.      jna short @@test_events     ; size is 4096k bytes or less.
  365.  
  366. @@test_events:
  367. ;
  368. ; TEST button event flags passed to handler in register AX
  369. ; In: AX=mouse event bits from device driver
  370. ;
  371. @@tst_moved:
  372.       test ax,M_MOVED           ; mouse was moved
  373.         jz short @@tst_released
  374.       jmp @@mouse_moved
  375. @@tst_released:
  376.       test ax,M_LT_RELEASED     ; a button was released
  377.         jz  short @@tst_right
  378.         jmp @@left_released
  379. @@tst_right:
  380.       test ax,M_RT_PRESSED      ; button2 (right on 2-button mouse)
  381.         jz short @@tst_left
  382.       jmp @@test_shift_right
  383. @@tst_left:
  384.       test ax,M_LT_PRESSED      ; button1 (left button)
  385.         jz short @@tst_middle
  386.         jmp  @@test_shift_left
  387. @@tst_middle:
  388.       test ax,M_MI_PRESSED      ; button3 (middle on mouse systems)
  389.         jz short @@tst_exit
  390.       jmp @@middle_pressed
  391. @@tst_exit:
  392. @@exit1:
  393.       jmp @@exit
  394. ;
  395. ; END of TEST button events
  396. ;
  397.  
  398. @@left_released:
  399.       cmp flag_Left,TRUE         ; If left not pressed, then hide mouse.
  400.         jne short @@skip_cursor
  401.       cmp flag_double,TRUE
  402.        je @@copy_region1
  403.       mov ax,NextPositionLeft
  404.       cmp ax,PositionLeft
  405.         jz  short @@no_selection ; nothing at all marked
  406. @@copy_region:                   ; Something to copy
  407.       cmp flag_Left,FALSE        ; If left not pressed, then hide mouse.
  408.         je short @@skip_cursor
  409. @@copy_region1:
  410.       mov flag_double,FALSE      ; Otherwise, copy screen text to
  411.       mov flag_Highlight,TRUE    ; the pastebuffer.
  412.       mov flag_Left,FALSE
  413.       call Fill_pastebuffer
  414.       cmp flag_pastebuffer,1     ; Pasting enabled?
  415.         jne short @@copy_region2 ; No, then maybe send Xterm info
  416.       or ax,ax                   ; Any chars copied to pastebuffer?
  417.        jz short @@skip_cursor    ; No, then hide mouse.
  418. @@copy_region2:
  419.       mov flag_doButton13,TRUE   ; Send button1+button3 info
  420.       jmp short @@skip_cursor
  421.  
  422. @@no_selection:
  423. ; Mouse was released at same location. Test if enough time has
  424. ; elapsed to call it a cursor positioning click.
  425.       call ClickTimeCursor
  426.         jnz short @@skip_cursor  ; Not enough time, hide mouse.
  427.       call set_cursor        ; set text cursor position
  428. @@skip_cursor:
  429.       mov flag_Left,FALSE
  430.       cmp flag_MouseOn,TRUE  ; turn off mouse cursor
  431.         jnz short @@no_hide  ; because it confusing to have
  432.       call HIDE_MOUSE        ; two cursors after we move the
  433.       mov flag_MouseOn,FALSE ; text cursor or highlight an area
  434. @@no_hide:
  435. @@exit2:
  436.       jmp @@exit
  437.  
  438. ; TOGGLE: shift-button2 == pastebuffer ON/OFF
  439. @@test_shift_right:
  440.       test byte ptr [ds:17h],3 ; Keyboard flag, bit 0 and bit 1 = SHIFT
  441.         jz short @@rt_pressed
  442.       mov al,1
  443.       sub al,flag_pastebuffer
  444.       mov flag_pastebuffer,al
  445.       jmp short @@exit2
  446. ;
  447. ; TOGGLE /A1-/A3 states by mouse actions
  448. ; button1+button2 == toggle to next of /A1 to /A3 in circular fashion.
  449. ;
  450. @@rt_pressed:
  451.       cmp flag_Left,TRUE
  452.         jz short @@exit2     ; both buttons simultaneously pressed
  453. @@do_insert:
  454. ;
  455. ; If ALT-button2, then simulate button 3 on 3-button mouse
  456. ;
  457.       test byte ptr [ds:17h],8 ; Keyboard flag, bit 3 = ALT
  458.         jnz  short @@do_insert0
  459.       mov flag_doButton2,TRUE; Send button2 info later on
  460.         jmp short @@do_insert1
  461. @@middle_pressed:            ; Extra mouse button pressed (button3)
  462. @@do_insert0:                ; or equivalent ALT-button2 was pressed
  463.       mov flag_doButton3,TRUE; Send button3 info later on
  464.       jmp short @@exit2      ; No paste, we are done!
  465. @@do_insert1:
  466.  
  467.       cmp flag_pastebuffer,1 ; Are we pasting the buffer?
  468.        jne short @@test_ctrl ; No, then go test for ctrl key
  469.       mov flag_Right,TRUE
  470.       mov bx,offset pastebuf
  471.       mov nextpair,bx        ; pointer reset to start of pastebuf
  472.  
  473. ; MOUSE ACTION: Add CR to end of pastebuffer output.
  474. ; If the right mouse button and CTRL were pressed, then
  475. ; set a flag to output a CR after the pastebuffer is finished.
  476. @@test_ctrl:
  477.       test byte ptr [ds:17h],4 ; Keyboard flag, bit 2 = CTRL
  478.         jz short @@test_ctrl1
  479.       mov  flag_CtrlRight,TRUE
  480. @@test_ctrl1:
  481. @@exit3:
  482.       jmp  @@exit
  483.  
  484. @@mouse_moved:
  485.       cmp flag_MouseOn,TRUE
  486.         jz  short @@is_on
  487.       call SHOW_MOUSE         ; switch on cursor after first movement
  488.       mov flag_MouseOn,TRUE
  489. @@is_on:
  490.       cmp flag_Left,TRUE
  491.         jz short @@do_mark    ; highlight if left button still pressed
  492.       jmp @@exit
  493. @@do_mark:
  494.       call highlight_text     ; In: cx,dx = mouse X,Y
  495.       jmp short @@exit3       ; Updates NextPositionLeft.
  496. ;
  497. ; TOGGLE: shift-button1 == Arrowkeys ON/OFF
  498. @@test_shift_left:             ; Test keyboard flag byte
  499.       test byte ptr [ds:17h],4 ; bit 2 = CTRL
  500.         jz short @@test_left_shift1
  501.       jmp @@exit               ; Nothing for ALT-left or CTRL-left
  502. @@test_left_shift1:
  503.       test byte ptr [ds:17h],3 ; bit 1 = LEFT SHIFT, bit 0 = RIGHT SHIFT
  504.         jz short @@left_pressed
  505.       test byte ptr [ds:17h],8 ; bit 3 = ALT
  506.         jnz short @@test_left1
  507.       mov al,1
  508.       sub al,flag_arrowkeys    ; Toggle the flag on/off (1 or 0)
  509.       mov flag_arrowkeys,al
  510.       jmp  short @@exit
  511. @@test_left1:
  512.       mov al,flag_editor
  513.       inc al
  514.       cmp al,MAX_of_A        ; Toggle the cursor positioning
  515.         jb short @@left1
  516.       mov al,1
  517. @@left1:                     ; Flag will be 1,2,..,(MAX_of_A-1)
  518.       mov flag_editor,al
  519.         jmp short @@exit     ; toggle finished
  520.  
  521. @@left_pressed:              ; get screen data after left click
  522.       mov ax,[ds:4ah]        ; Characters per row for this video mode
  523.       mov lineSize,ax
  524.       mov ax,[ds:4eh]        ; Offset for current video page
  525.       mov videoOffset,ax
  526.       mov ax,[ds:63h]        ; Mono/Color BIOS word
  527.       cmp ax,3B4h            ; monochrome ?
  528.       mov videosegment,0b000h ; mono address
  529.         jz short @@left_pressed1
  530.       mov videosegment,0b800h ; color address
  531. @@left_pressed1:
  532.       call unhighlight_text     ; remove previous highlighting
  533.       mov flag_Right,FALSE
  534.       mov counter_blanks,0
  535.       mov flag_Left,TRUE        ; Set left button press state
  536.       call xy2offs              ; In: cx,dx   Out: ax
  537.       mov PositionLeft,ax       ; Save mouse position and reset both
  538.       mov NextPositionLeft,ax   ; because selected text was trashed.
  539.       sub ax,2
  540.       mov xor_pointer,ax
  541.  
  542. ; SPEED_LDC is the number of ticks of the system clock, 18.2 per
  543. ; second, in which a left double-click must occur. Shorter times
  544. ; are not considered double-click candidates.
  545.  
  546.       mov flag_double,FALSE  ; Assume not a double-click.
  547.       call ClickTimeDouble   ; Uses: AX
  548.         jz short @@exit      ; Not enough time.
  549. ; double click
  550.       mov flag_double,TRUE
  551.       call highlight_word
  552. @@exit:
  553.       call stuff2keybuffer   ; to end a possibly active int 16h,0
  554.       pop ds
  555.       XPOPA
  556.       ret
  557. MouseHandler endp
  558.  
  559. SHOW_MOUSE proc
  560.     push ax
  561.     mov ax,1                ; Function show mouse
  562.     int 33h
  563.     pop ax
  564.     ret
  565. SHOW_MOUSE endp
  566.  
  567. HIDE_MOUSE proc
  568.     push ax
  569.     mov ax,2                ; Function hide mouse
  570.     int 33h
  571.     pop ax
  572.     ret
  573. HIDE_MOUSE endp
  574.  
  575. ; calculate video offset from x and y
  576. ; In:  x=cx, y=dx ; Left upper corner of screen is x=0, y=0.
  577. ; Out: ax := offs = y*80+x
  578. ; USES: ax
  579. xy2offs proc
  580.       PUSHR <dx,cx>
  581.       shr cx,1
  582.       shr cx,1
  583.       shr cx,1
  584.       cmp lineSize,40
  585.       jnz short @@no_40
  586.       shr cx,1         ; divide by 16 if there are 40 columns per line
  587.     @@no_40:
  588.       shr dx,1
  589.       shr dx,1
  590.       shr dx,1
  591.       mov ax,dx
  592.       mul lineSize
  593.       add ax,cx        ; +=x
  594.       add ax,ax        ; 2 bytes per character
  595.       add ax,videoOffset
  596.       inc ax           ; -> attribute
  597.       POPR <cx,dx>
  598.       ret
  599. xy2offs endp
  600.  
  601. ;
  602. ; Calculate from offset into screen memory the screen row, col
  603. ; Left upper corner of screen is row=0, col=0 [rows 0..24, cols 0..79]
  604. ; In: ax=offset into screen memory (includes attribute counts).
  605. ; Out: ah := col, al = row
  606. offs2xy proc
  607.       push bx
  608.       shr ax,1               ; divide numerator AX by 2
  609.       mov bx,lineSize        ; bl=denominator
  610.       idiv bl                ; AX/bl --> al=quotient, ah=remainder
  611.       pop bx
  612.       ret
  613. offs2xy endp
  614.  
  615. ; show or hide mark on screen
  616. ; In: AX=characters*2 for XOR operation
  617. ; USES: AX
  618. xor_screen proc
  619.       PUSHR <bx,cx,dx,ds>
  620.       call HIDE_MOUSE        ; in order not to destroy the mouse cursor
  621.       mov bx,xor_pointer
  622.       mov cl,xor_mask
  623.       mov dx,videosegment
  624.       mov ds,dx
  625.       sar ax,1               ; Divide by 2 to get number of characters
  626.       or  ax,ax
  627.       jns short @@pos_loop
  628.  
  629. ; mouse was moved to the left
  630. @@neg_loop:
  631.       xor byte ptr [ds:bx],cl   ; xor_mask applied to screen byte
  632.       sub bx,2
  633.       inc ax      ; inc, as counter is negative
  634.       jnz short @@neg_loop
  635.       jmp short @@exit
  636. ; mouse was moved to the right
  637. @@pos_loop:
  638.       add bx,2
  639.       xor byte ptr [ds:bx],cl
  640.       dec ax
  641.       jnz short @@pos_loop
  642. @@exit:
  643.       call SHOW_MOUSE
  644.       mov xor_pointer,bx
  645.       POPR <ds,dx,cx,bx>     ;   PUSHR <bx,cx,dx,ds>
  646.     ret
  647. xor_screen endp
  648.  
  649. ; Highlight single word chosen by double click
  650. ; USES: AX
  651. highlight_word proc
  652.       PUSHR <bx,ds>
  653.       mov lasttime,0
  654.       mov lasttime+2,0         ; prevent Triple click
  655.       push videosegment
  656.       pop ds
  657.       mov bx,PositionLeft      ; point to attribute
  658.       dec bx
  659.       call @@tst_letter
  660.       jc @@exit                ; clicked to void
  661.   @@go_left:                   ; search for word begin
  662.       call @@tst_letter
  663.       dec bx
  664.       dec bx
  665.       jnc  @@go_left
  666.       add bx,5                 ; points to attribute again
  667.       mov  PositionLeft,bx
  668.       dec bx
  669.       dec bx
  670.       mov  xor_pointer,bx
  671.       dec  bx
  672.   @@go_right:                  ; search for word end
  673.       inc bx
  674.       inc bx
  675.       call @@tst_letter
  676.       jnc @@go_right
  677.       mov ax,bx
  678.       inc bx
  679.       mov NextPositionLeft,bx
  680.       sbb ax,xor_pointer       ; cy is 1 from tst_let
  681.       call xor_screen          ; Uses ax
  682.   @@exit:
  683.       POPR <ds,bx>
  684.       ret
  685.  
  686. ; @@tst_letter --- Test character classes.
  687. ; Do this like Xterm, with a string of data pairs:
  688. ; 35:35,45:57,64:90,95:95,97:122,128:165
  689. ; USES: AX
  690. ;
  691.   @@tst_letter:
  692.       push si
  693.       mov ax,offset unix_ranges
  694.       mov si,ax
  695.       mov ah,0
  696.       mov al,[ds:bx]
  697.   @@tst_loop:
  698.       cmp ah,unix_pairs
  699.       je @@tst_failed
  700.       inc ah
  701.       cmp byte ptr [cs:si],al
  702.       jbe short @@tst_1
  703.       inc si
  704.       inc si
  705.       jmp short @@tst_loop
  706.   @@tst_1:
  707.       inc si
  708.       cmp al,byte ptr [cs:si]
  709.       jbe short @@tst_worked
  710.       inc si
  711.       jmp short @@tst_loop
  712.   @@tst_worked:
  713.       clc
  714.       jmp short @@tst_exit
  715.   @@tst_failed:
  716.       stc
  717.   @@tst_exit:
  718.       pop si
  719.       ret
  720. highlight_word endp
  721. ;
  722. ; Highlight screen area that was traversed during mouse motion.
  723. ; In: cx,dx = mouse X,Y
  724. ; USES: AX
  725. highlight_text proc
  726.       call xy2offs            ; In: cx,dx   Out: ax
  727.       push ax                 ; New left mouse position
  728.       sub ax,NextPositionLeft ; ax/2 == number of positions traversed
  729.       pop NextPositionLeft    ; update new mouse position
  730.       jz short @@exit         ; too little mouse motion
  731.       call xor_screen         ; In: AX=number positions times 2
  732.       mov flag_Highlight,TRUE
  733.     @@exit:
  734.       ret
  735. highlight_text endp
  736.  
  737. ; Remove highlight from screen area.
  738. ; Uses: AX
  739. unhighlight_text proc
  740.     push bx
  741.       cmp flag_Highlight,TRUE
  742.         jnz short @@exit     ; Highlighting was already undone.
  743.       mov bx,PositionLeft
  744.       mov ax,NextPositionLeft
  745.       sub ax,bx
  746.         je  short @@exit     ; Nothing highlighted
  747.       mov bx,PositionLeft
  748.       dec bx
  749.       dec bx
  750.       mov xor_pointer,bx     ; Set pointer into screen memory
  751.       call xor_screen        ; Unhighlight. Uses: AX=Length of region
  752.       mov flag_Highlight,FALSE
  753.    @@exit:
  754.    pop bx
  755.    ret
  756. unhighlight_text endp
  757.  
  758. ;
  759. ; Fill_pastebuffer: Read the selected characters into pastebuffer.
  760. ; Called after double click or left selection.
  761. ;
  762. Fill_pastebuffer proc
  763.       PUSHR <bx,cx,dx,si,di,es>
  764.       cmp flag_pastebuffer,1     ; Are we supposed to paste?
  765.         jne short @@exit_nochars ; No, then quit with no chars.
  766.       push cs                ; Yes, then fool with pastebuffer
  767.       pop es                 ; store chars to es:di
  768.       mov bx,PositionLeft
  769.       mov cx,NextPositionLeft
  770.       dec bx
  771.       dec cx                 ; doesn't point to attribute any more now
  772.       mov dx,2
  773.       mov di,offset pastebuf
  774.       cmp bx,cx
  775.         jc  short @@no_swap  ; not marked from right to left
  776.         jz  short @@exit_nochars     ; nothing at all marked
  777.       xchg bx,cx             ; now from left to right
  778.       add bx,dx
  779.       add cx,dx
  780.       cmp bx,cx
  781.         jnz short @@no_swap  ; something marked
  782. @@exit_nochars:              ; Nothing marked
  783.       mov ax,0
  784.       jmp @@@exit
  785. @@no_swap:
  786.       cld
  787.       mov ax,videosegment
  788.       mov ds,ax
  789.       mov ah,0
  790.  
  791. @@rd_loop:
  792.       cmp di,EndOfBuffer
  793.         ja short @@no_bln_left  ; Buffer is full
  794.       mov al,[ds:bx]
  795.       cmp al,' '
  796.         ja short @@normal_char
  797.       inc ah                 ; ah == compression count for ' '
  798.       cmp ah,32              ; ah == 32 means 32 ' ' characters.
  799.         jnz short @@next_char
  800.       stosb                  ; Otherwise, store coded byte
  801.       mov ah,0               ; and continue with the next one
  802.       jmp short @@next_char
  803.  
  804. @@normal_char:
  805.       cmp ah,0               ; are there blanks left unstored ?
  806.         jz short @@no_blks   ; no, it's a normal char
  807.       xchg al,ah             ; yes, it's a coded ' '
  808.       stosb                  ; Squirrel away coded ' ' byte
  809.       xchg al,ah
  810.       mov ah,0               ; Attribute byte is 0 for coded ' '
  811. @@no_blks:
  812.       stosb                  ; store char, coded or otherwise
  813.  
  814. @@next_char:
  815.       add bx,dx              ; next char on screen
  816.  
  817. ; Test, if at line end on screen
  818. ; condition: screen pos mod (characters per line) == 0
  819.  
  820.       PUSHR <dx,cx,ax>
  821.       xor dx,dx              ; must be 0 before divide
  822.       mov ax,bx              ; screen pos
  823.       sub ax,videoOffset
  824.       mov cx,lineSize        ; CX == 40 or CX == 80
  825.       add cx,cx              ; *2 because of ascii,attribute
  826.       div cx
  827.       or dx,dx               ; Division remainder == 0 ?
  828.         jnz short @@not_eol
  829.  
  830. @@go_back:                   ; discard blanks until end of line
  831.       dec di
  832.       cmp byte ptr [es:di],' '
  833.         ja  short @@no_back
  834.       cmp byte ptr [es:di],0 ; end of previous line ?
  835.         ja short @@go_back
  836. @@no_back:
  837.       inc di
  838.       mov al,dl              ; 0 to mark end of line
  839.       stosb
  840.       pop ax                 ; ax must have been pushed last
  841.       xor ah,ah              ; Zero the ' ' counter
  842.       push ax
  843. @@not_eol:
  844.       POPR <ax,cx,dx>
  845.       cmp bx,cx              ; at the end of selected area ?
  846.         jnz short @@rd_loop
  847.       or ah,ah               ; blanks left to store ?
  848.         jz short @@no_bln_left
  849.       mov al,ah
  850.       stosb                  ; store remaining blanks
  851. @@no_bln_left:
  852.       mov lastpair,di        ; pointer to end of used buffer area
  853.  
  854. @@exit:
  855.       mov ax,1
  856. @@@exit:
  857.       POPR <es,di,si,dx,cx,bx>  ; PUSHR <bx,cx,dx,si,di,es>
  858.       ret
  859. Fill_pastebuffer endp
  860.  
  861. ; ClickTimeDouble --- Return Z if time since last left click too short.
  862. ; Uses: AX
  863. ClickTimeDouble proc
  864.       PUSHR <cx,dx>
  865.       mov ah,0
  866.       int 1ah                ; read system clock counter
  867.       mov ax,0               ; Return AX==0 in Z flag
  868.       push cx                ; high word
  869.       push dx                ; low word
  870.       sub  dx,lasttime
  871.       sbb  cx,lasttime+2     ; cx:dx = ticks since last click
  872.       pop  cs:lasttime
  873.       pop  cs:lasttime+2     ; save new clock time
  874.       or cx,cx
  875.         jnz short @@exit     ; Exceeded 65535/18.2 seconds
  876.       cmp dx,SPEED_LDC
  877.         ja short @@exit      ; Exceeded SPEED_LDC seconds
  878.       mov ax,1               ; Was a double-click.
  879. @@exit:
  880.      or ax,ax
  881.      POPR <dx,cx>
  882.      ret
  883. ClickTimeDouble endp
  884.  
  885. ; ClickTimeCursor --- Return Z if time since last left click too short.
  886. ; Uses: AX
  887. ClickTimeCursor proc
  888.       PUSHR <cx,dx>
  889.       mov ah,0
  890.       int 1ah                ; read system clock counter
  891.       mov ax,0               ; Return AX==0 in Z flag
  892.       sub  dx,lasttime
  893.       sbb  cx,lasttime+2     ; cx:dx = ticks since last left press
  894.       or cx,cx
  895.         jnz short @@exit     ; Exceeds 65535/18.2 seconds
  896.       cmp dx,SPEED_LC
  897.         ja short @@exit      ; Exceeds 3/18.2 seconds
  898.       mov ax,1
  899. @@exit:
  900.      or ax,ax
  901.      POPR <dx,cx>
  902.      ret
  903. ClickTimeCursor endp
  904.  
  905. ; install mouse handler
  906.  
  907. InstallMouseHandler proc far
  908.       PUSHR <es,dx,cx,ax>
  909.  
  910. ; Software Reset, to put handler into defined state
  911.       mov ax,21h
  912.       int 33h
  913.       push cs
  914.       pop  es
  915.  
  916.       mov dx,offset MouseHandler
  917.       mov cx,(M_MOVED or M_LT_PRESSED or M_LT_RELEASED or M_RT_PRESSED or M_MI_PRESSED)
  918.       mov ax,14h             ; Swap Interrupt Subroutines
  919.       int 33h
  920.                              ; ignore old interrupt routine
  921.       POPR <ax,cx,dx,es>
  922.       ret
  923. InstallMouseHandler endp
  924.  
  925. ; Get characters from the paste buffer
  926. ; Characters are 33 to 255
  927. ; A character nnn less than 33 represents nnn Blanks
  928. ; End of line is marked with 0
  929. ;
  930. INCZ macro op  ; if Z op++
  931. local not_zero
  932. jnz short not_zero
  933. inc op
  934. not_zero:
  935. endm
  936.  
  937. ; In: Nothing
  938. ; Out: ZF flag == buffer empty else AL == char found
  939. ; Uses: AX, flags
  940. ;
  941. GetPastebuffer2AL proc
  942.       push bx
  943.       cmp flag_pastebuffer,0
  944.         jz short @@buf_empty
  945.       cmp flag_Right,FALSE
  946.         jz  short @@buf_empty
  947.       cmp counter_blanks,0
  948.         jz  short @@no_bln_lft
  949.       dec counter_blanks
  950.       INCZ nextpair
  951.       mov al,' '
  952.       jmp short @@char_found
  953.  
  954. @@no_bln_lft:
  955.       mov bx,nextpair
  956.       cmp bx,lastpair
  957.         jnz short @@not_empty
  958.       cmp flag_CtrlRight,TRUE     ; append CR, too ?
  959.         jnz short @@buf_empty
  960.       mov flag_CtrlRight,FALSE    ; Mark that we did it.
  961.       mov al,13                   ; return CR
  962.       jmp short @@char_found
  963.  
  964. @@not_empty:
  965.       mov al,[cs:bx]              ; get next character
  966.       cmp al,0                    ; end of line ?
  967.         jnz short @@not_eol
  968.       mov al,13
  969.       inc nextpair
  970.       jmp short @@char_found
  971.  
  972. @@not_eol:
  973.       cmp al,' '
  974.         jbe short @@blanks
  975.       inc nextpair
  976.       jmp short @@char_found
  977. @@blanks:
  978.       mov ah,al
  979.       mov al,' '
  980.       dec ah
  981.       mov counter_blanks,ah
  982.       INCZ nextpair           ; blanks exhausted
  983. @@char_found:
  984.       clc
  985.       jmp short @@exit
  986. @@buf_empty:
  987.       stc
  988. @@exit:
  989.       pop bx
  990.       ret
  991. GetPastebuffer2AL endp
  992.  
  993.  
  994. ; Patch for EXEC Function
  995.  
  996. new_21h proc
  997.       cmp ax,4b00h           ; exec
  998.       jz short @@new_exec
  999.         jmp @@doit
  1000. @@new_exec:
  1001.  
  1002. ; activate mouse handler, as it is possible,
  1003. ; that a program that changed the mouse handler
  1004. ; did so by starting COMMAND.COM
  1005.  
  1006.       push bp
  1007.       mov  bp,sp
  1008.  
  1009. ; stack now:
  1010. ; bp   -> bp
  1011. ; bp+2 -> ip
  1012. ; bp+4 -> cs
  1013. ; bp+6 -> flags
  1014.  
  1015.       XPUSHA
  1016.       push es
  1017.       mov cx,0               ; get old interrupt info
  1018.       mov  ax,14h            ; Swap interrupt subroutines
  1019.       int 33h
  1020.       mov old_mousemask,cx   ; save old mouse mask
  1021.       mov old_mouseAddr,dx
  1022.       mov old_mouseAddr+2,es ; save address of old routine
  1023.  
  1024.       call InstallMouseHandler
  1025.       pop es
  1026.       XPOPA
  1027.       push old_mousemask          ; push to enable recursion
  1028.       push old_mouseAddr
  1029.       push old_mouseAddr+2
  1030.  
  1031.       push [bp+6]            ; take flags of original int and
  1032.                              ; simulate int operation
  1033.       call dword ptr [cs:old_21h]
  1034.  
  1035. ; iret after original int 21h leads to here
  1036.       pop  old_mouseAddr+2
  1037.       pop  old_mouseAddr
  1038.       pop  old_mousemask
  1039.       pop bp
  1040.       pushf
  1041.       XPUSHA
  1042.       mov ax,21h             ; Software Reset
  1043.       int 33h
  1044.       cmp cs:killed_flg,TRUE ; /U in the mean time ?
  1045.       jz short @@no_res_old
  1046.       mov cx,old_mousemask ; set old routine again
  1047.       les dx,dword ptr old_mouseAddr
  1048.       mov ax,14h
  1049.       int 33h
  1050. @@no_res_old:
  1051.       XPOPA
  1052.       popf
  1053.       retf 2                 ; ignore old flags as EXEC returns
  1054.                              ; result status in flag register
  1055. @@doit:
  1056.         db 0eah ; jmp far
  1057. old_21h dw 0,0
  1058. killed_flg db FALSE
  1059.  
  1060. new_21h endp
  1061.  
  1062.  
  1063. ; Patch for Interrupt 10h
  1064.  
  1065. old_10h dw 0,0
  1066.  
  1067. new_10h proc
  1068.       cmp flag_MouseOn,TRUE
  1069.         jnz short @@no_hide
  1070.       call HIDE_MOUSE
  1071.       mov flag_MouseOn,FALSE
  1072. @@no_hide:
  1073.       cmp flag_Highlight,TRUE
  1074.         jnz short @@no_un_sel
  1075.       push ax
  1076.       call unhighlight_text     ; Uses AX
  1077.       pop ax
  1078.       mov flag_Left,FALSE
  1079. @@no_un_sel:
  1080.       pushf                     ; simulate int
  1081.       inc counter_int10         ; Mark int 10h active
  1082.       call dword ptr [old_10h]
  1083.       dec counter_int10         ; Mark int 10h inactive
  1084.       iret
  1085. new_10h endp
  1086.  
  1087. ; BIOD data segment equates
  1088. ;
  1089. biosdata segment at 40h
  1090. org 1ah
  1091. headptr dw (?)  ; pointer to next key entry to read
  1092. tailptr dw (?)  ; pointer to last read key entry
  1093. org 80h
  1094. bufstrt dw (?)  ; pointer to start keyboard buffer
  1095. bufend  dw (?)  ; pointer to end keyboard buffer
  1096. biosdata ends
  1097.  
  1098. stuffkeyCX proc
  1099. ; substitute for Int 16h, function 5
  1100. ; in:  ch=scan code
  1101. ;      cl=ascii
  1102. ; out: al=0 success
  1103. ;      al=1 buffer full
  1104. ; USES: ax,cx
  1105. ;
  1106.    push ds
  1107.    push bx
  1108.    pushf
  1109.     cli
  1110.     mov ax,biosdata
  1111.     mov ds,ax
  1112.     mov ax,ds:tailptr
  1113.     add ax,2
  1114.     mov bl,1
  1115.     cmp ax,ds:headptr ; don't want tailptr == headptr after exit
  1116.     jz  short @@full  ; because it means buffer is empty!
  1117.     cmp ax,ds:bufend  ; Ringbuffer, may need to bump pointer
  1118.     jnz short @@no_wrap
  1119.     mov ax,ds:bufstrt ; wrap around was required
  1120. @@no_wrap:            ; AX == new tailptr position
  1121.     cmp ax,ds:headptr ; don't want tailptr == headptr after exit
  1122.     jz  short @@full  ; because it means buffer is empty!
  1123. @@go_ahead:
  1124.     mov bx,ds:tailptr ; old tailpointer
  1125.     mov [ds:bx],cx    ; store scan+ascii
  1126.     mov ds:tailptr,ax
  1127.     mov bl,0
  1128. @@full:
  1129.     mov al,bl
  1130.    popf
  1131.    pop bx
  1132.    pop ds
  1133.    or  al,al              ; 0 == save was successful
  1134.    ret                    ; sti not appropriate here
  1135. stuffkeyCX endp
  1136. ;
  1137. ; Test keyboard buffer for room to copy scan codes
  1138. ; In: AL == # scan codes
  1139. ; Out: NZ flag set if no room exists
  1140. ; Uses: AX, FLAGS
  1141. Check4Room proc
  1142.    PUSHR <ds,bx,ax>
  1143.     mov bl,al           ; Number of pairs required
  1144.     mov ax,biosdata
  1145.     mov ds,ax
  1146.     mov ax,ds:tailptr
  1147. @@loop:
  1148.     add ax,2
  1149.     cmp ax,ds:bufend  ; Ringbuffer, may need to bump pointer
  1150.       jnz short @@no_wrap
  1151.     mov ax,ds:bufstrt ; wrap around was required
  1152. @@no_wrap:            ; AX == new tailptr position
  1153.     cmp ax,ds:headptr ; don't want tailptr == headptr after exit
  1154.     jz  short @@full  ; because it means buffer is empty!
  1155. @@go_ahead:
  1156.     dec bl
  1157.     or bl,bl
  1158.     jnz short @@loop
  1159. @@full:
  1160.    or  bl,bl              ; 0 == it worked, NZ == failed
  1161.    POPR <ax,bx,ds>
  1162.    ret
  1163. Check4Room endp
  1164. ;
  1165. ; Patch for int 1ch
  1166. ;
  1167. new_1ch proc
  1168.       pushf
  1169.       cmp flag_busy_stuffing,1  ; In routine "stuff2keybuffer"?
  1170.         je @@skip            ; wait until next timer tick
  1171.       call stuff2keybuffer   ; write characters into keyboard buffer
  1172. @@skip:
  1173.       popf
  1174.       db 0eah                ; Code for jmp far
  1175. old_1ch dw 0,0
  1176. new_1ch endp
  1177.  
  1178. ; Patch for int 16h
  1179.  
  1180. new_16h proc
  1181.       cmp  ah,MOUSE_FN       ; New function for int 16h
  1182.         jnz  short @@skip1
  1183.       dec  ah                ; AH unchanged by normal bios call
  1184.       mov  cx,IDENTCODE      ; Return identity code
  1185.       push cs                ; and far address of the pastebuffer
  1186.       pop  es                ; es:bx := buffer address
  1187.       mov  bx,offset pastebuf
  1188.       iret
  1189. @@skip1:
  1190.       pushf
  1191.       cmp flag_busy_stuffing,1  ; In routine "stuff2keybuffer"?
  1192.         je @@skip2           ; wait until next timer tick
  1193.       call stuff2keybuffer   ; else, write character into keyboard buffer
  1194. @@skip2:
  1195.       popf
  1196.       db 0eah                ; Code for jmp far
  1197. old_16h dw 0,0
  1198. new_16h endp
  1199.  
  1200. ;
  1201. ; Arrow key routines, does not depend on Xterm standard.
  1202. ;
  1203. LeftArrow proc
  1204.       mov cx,4b00h      ;cl=0, ch=4bh Left arrow key
  1205.       call stuffkeyCX   ; uses ax,cx
  1206.       ret
  1207. LeftArrow endp
  1208. DownArrow proc
  1209.       mov cx,5000h      ;cl=0, ch=50h Down arrow key
  1210.       call stuffkeyCX   ; uses ax,cx
  1211.       ret
  1212. DownArrow endp
  1213. UpArrow proc
  1214.       mov cx,4800h      ;cl=0, ch=48h Up arrow key
  1215.       call stuffkeyCX   ; uses ax,cx
  1216.       ret
  1217. UpArrow endp
  1218. RightArrow proc
  1219.       mov cx,4d00h      ;cl=0, ch=4dh Right arrow key
  1220.       call stuffkeyCX   ; uses ax,cx
  1221.       ret
  1222. RightArrow endp
  1223.  
  1224. ;
  1225. ; Xterm standard uses the sequence "ESC [ M cb cx cy" where
  1226. ; cb=32 for press left-button, cb=34 for press right-button, cb=33 for
  1227. ; press middle button, cb=35 for release (any) button, cx=32+1+col,
  1228. ; cy=32+1+row where (0,0) is upper left corner of screen
  1229. ;
  1230. ; Stuff a string of scan code data into the keyboard buffer
  1231. ;
  1232. ; In: bx=offset to string, al=number of pairs
  1233. ; Uses: ax,bx
  1234. ;
  1235. ; The string must fit all at once for this procedure to succeed.
  1236. ; We test the keyboard buffer to see if there is room to do the copy.
  1237. ; If not enough room, then the call fails!
  1238. ;
  1239. StuffCodes2keybuffer proc
  1240.       push cx
  1241.       cmp flag_arrowkeys,0    ; Arrow and Xterm stuffing disabled?
  1242.         je short @@exit       ; Yes, then quit fast.
  1243. ; Test for room to do the copy
  1244.       call Check4Room         ; Does the keyboard buffer have room
  1245.         jnz short @@exit      ; for AL pairs? NZ flag == NO ROOM, Exit!
  1246. @@loop:
  1247.       cmp al,0
  1248.       je @@exit
  1249.       dec al
  1250.       mov cl,byte ptr [cs:bx]      ; ASCII value
  1251.       inc bx
  1252.       mov ch,byte ptr [cs:bx]      ; Scan code
  1253.       inc bx
  1254.       push ax
  1255.       call stuffkeyCX              ; uses ax,cx
  1256.       pop ax
  1257.       jmp @@loop
  1258. @@exit:
  1259.       pop cx
  1260.       ret
  1261. StuffCodes2keybuffer endp
  1262.  
  1263. ; Stuff cursor location into data area using Xterm codes
  1264. ; In: al=Y=row, ah=Y=col, the cursor location in PC terms.
  1265. ;     bx=offset to data area
  1266. ; Uses: ax,bx
  1267. ; Xterm codes are ROW=X+' '+1, COL=Y+' '+1.
  1268. ; Xterm_PAD==' '+1. Assume fake scan codes.
  1269. ;
  1270. StuffLoc2buffer proc
  1271.       add ah,Xterm_PAD          ; coded col for Xterm
  1272.       mov byte ptr [cs:bx],ah
  1273.       inc bx
  1274.       inc bx
  1275.       add al,Xterm_PAD          ; coded row for Xterm
  1276.       mov byte ptr [cs:bx],al
  1277.       ret
  1278. StuffLoc2buffer endp
  1279.  
  1280. ; Stuff left button info into keyboard buffer
  1281. ; In: al=row, ah=column
  1282. ; Uses: ax
  1283. ;
  1284. StuffLeftButton proc
  1285.       push bx
  1286.       mov bx,offset Button1_COL ; Offset to data area
  1287.       call StuffLoc2buffer      ; Stuff cursor location into buffer
  1288.       mov bx,offset Button1_ESC ; Escape sequence for button 1
  1289.       mov al,Button1_LEN        ; Number of pairs in button 1 escape.
  1290.       call StuffCodes2keybuffer ; Stuff escape seq into key buffer
  1291.       pop bx
  1292.       ret
  1293. StuffLeftButton endp
  1294.  
  1295. ; Simulate press of button 3 on any mouse. Left release is mapped to
  1296. ; the press of button three which normally follows button one. This button
  1297. ; ends the marking of a region and maybe it copies it too, depending on the
  1298. ; client program at the remote host end.
  1299. ;
  1300. StuffRightButton proc
  1301. ; In: al=row, ah=column
  1302. ; Uses: ax
  1303. ; We assume the keyboard buffer empty!
  1304. ; Simplifies logic, but may fail.
  1305.       push bx
  1306.       mov bx,offset Button3_COL ; Data area pointer
  1307.       call StuffLoc2buffer      ; Stuff cursor location into buffer
  1308.       mov bx,offset Button3_ESC ; Escape sequence for button 3
  1309.       mov al,Button3_LEN        ; Number of pairs in button 3 escape.
  1310.       call StuffCodes2keybuffer ; Stuff escape seq into key buffer
  1311.       pop bx
  1312.       ret
  1313. StuffRightButton endp
  1314.  
  1315. ;
  1316. ; Simulate button2 press on any mouse.
  1317. ;
  1318. StuffMiddleButton proc
  1319. ; In: al=row, ah=column
  1320. ; Uses: ax
  1321. ; We assume the keyboard buffer empty!
  1322. ; Simplifies logic, but may fail.
  1323.       push bx
  1324.       mov bx,offset Button2_COL ; Data area pointer
  1325.       call StuffLoc2buffer      ; Stuff cursor location into buffer
  1326.       mov bx,offset Button2_ESC ; Escape sequence for button 2
  1327.       mov al,Button2_LEN        ; Number of pairs in button 1 escape.
  1328.       call StuffCodes2keybuffer ; Stuff escape seq into key buffer
  1329.       pop bx
  1330.       ret
  1331. StuffMiddleButton endp
  1332.  
  1333. ;
  1334. ; Do Xterm selection by stuffing escapes into the keyboard buffer
  1335. ; Our selection here maps a button1 drag into "press left", "move"
  1336. ; and "press right", which is the 3-button Xterm standard for marking
  1337. ; a region.
  1338. ;
  1339. DoXtermButton1Button3 proc
  1340.       cmp flag_editor,3      ; Is it Xterm mode?
  1341.         jne short @@exit
  1342.       push cx
  1343.       mov ax,PositionLeft
  1344.       mov cx,NextPositionLeft
  1345.       cmp ax,cx
  1346.         jc  short @@no_swap  ; not marked from right to left
  1347.       xchg ax,cx             ; now from left to right
  1348. @@no_swap:
  1349. ; Send left button info
  1350.       push cx
  1351.       call offs2xy           ; AX/lineSize --> al=quotient, ah=remainder
  1352.       call StuffLeftButton   ; stuff Xterm escape for button 1
  1353. ; Send right button info, to simulate button3 on a 2-button mouse.
  1354.       pop ax                 ; prep for integer division, AX=top
  1355.       call offs2xy           ; AX/lineSize --> al=quotient, ah=remainder
  1356.       call StuffRightButton  ; stuff Xterm escape for button 3
  1357.       pop cx
  1358. @@exit:
  1359.       ret
  1360. DoXtermButton1Button3 endp
  1361.  
  1362. ;
  1363. ; Stuff middle button (button 2) info into the keyboard buffer
  1364. ; This button normally causes the remote client to insert the
  1365. ; local pastebuffer (Xterm standard).
  1366. ;
  1367. DoXtermButton2 proc
  1368.       cmp flag_editor,3      ; Is it Xterm mode?
  1369.         jne short @@exit
  1370.       call GetMousePosition  ;al=row, ah=col
  1371.       call StuffMiddleButton
  1372. @@exit:
  1373.       ret
  1374. DoXtermButton2 endp
  1375.  
  1376. ;
  1377. ; Stuff right button (button 3) info into the keyboard buffer
  1378. ; This button normally causes the remote client to define the
  1379. ; region after a left button was received (Xterm standard).
  1380. ; This is the extra button on a PC 3-button mouse.
  1381. ;
  1382. DoXtermButton3 proc
  1383.       cmp flag_editor,3      ; Is it Xterm mode?
  1384.         jne short @@exit
  1385.       call GetMousePosition  ;al=row, ah=col
  1386.       call StuffRightButton
  1387. @@exit:
  1388.       ret
  1389. DoXtermButton3 endp
  1390.  
  1391. ;
  1392. ; stuff2keybuffer --- Write characters into keyboard buffer
  1393. ;
  1394. stuff2keybuffer proc               ; stuff to keyboard buffer
  1395.       mov flag_busy_stuffing,1  ; Don't let the timer interrupt
  1396.                                 ; re-enter this routine!
  1397.       XPUSHA
  1398.       xor cx,cx
  1399.       xchg cl,lastChar       ; character left from last attempt
  1400.       or cl,cl               ; 0 == nothing left
  1401.         jnz short @@after_rd ; save character from last trial
  1402. @@loop:
  1403.       call GetPastebuffer2AL ; Nothing returned if flag_pastebuffer == 0
  1404.       mov cl,al              ; else AL == char found in pastebuffer
  1405.         jc short @@@exit     ; nothing to stuff into keybuffer
  1406. @@after_rd:
  1407.       push cx
  1408.       cmp cl,0
  1409.       mov ch,0               ; scancode, only relevant for ENTER
  1410.        jz @@scan_code        ; Potential trouble: wrong scan codes!
  1411.       mov ch,1ch             ; scancode for ENTER
  1412. @@scan_code:
  1413.       call stuffkeyCX        ; stuff CX to keyboard buffer, uses ax,cx
  1414.       pop cx
  1415.         jz  short @@loop     ; 0 == save was successful
  1416.       mov lastChar,cl        ; save for next time
  1417.       jmp @@exit
  1418.  
  1419. @@@exit:                     ; Get here because pasting is finished.
  1420.       mov lastChar,0
  1421.       call StuffArrows       ; Stuff arrow keys and Xterm sequences
  1422. @@exit:
  1423.       XPOPA
  1424.       mov flag_busy_stuffing,0  ; Let the timer interrupt
  1425.                                 ; re-enter this routine!
  1426.       ret
  1427. stuff2keybuffer endp
  1428.  
  1429. ;
  1430. ; Move cursor by stuffing keyboard buffer with escapes or arrow keys.
  1431. ;
  1432. StuffArrows proc
  1433. ;
  1434. @@arrows:
  1435. ;
  1436. ; emacs/vi: If the target row is not equal to the present row, then move
  1437. ;           the cursor to column one of the same line before doing any
  1438. ;           further cursor motion. Logic from emacs/vi/jed/jove.
  1439. ; matrix:   Move to row first, then to column, no tricky cursor moves.
  1440. ; xterm:    Use the escape sequence \033 [ M cb cx cy
  1441. ;           for left button press.
  1442. ;
  1443.       cmp flag_arrowkeys,1     ; Arrow keys on?
  1444.         je short @@test_emacs_vi
  1445.         jmp @@exit             ; No, then get out of here fast.
  1446. @@test_emacs_vi:
  1447.       cmp flag_editor,1        ; Using a method suitable for emacs/vi?
  1448.         jne short @@test_matrix
  1449.         jmp @@do_emacs_vi
  1450. @@test_matrix:
  1451.       cmp flag_editor,2        ; Using a method suitable for matrix editor?
  1452.         jne short @@test_xterm ; Test Xterm escapes
  1453.         jmp @@do_matrix        ; Do matrix method
  1454. @@test_xterm:
  1455.       cmp flag_editor,3
  1456.         je short @@do_xterm
  1457.       jmp @@exit
  1458. ;
  1459. @@do_xterm:
  1460.       cmp flag_doButton13,TRUE
  1461.         jne short @@do_xterm1
  1462.       call DoXtermButton1Button3 ; Send button 1 + button 3.
  1463.       mov flag_doButton13,FALSE
  1464.       jmp short @@do_xterm_exit
  1465. @@do_xterm1:
  1466.       cmp flag_doButton2,TRUE
  1467.         jne short @@do_xterm2
  1468.       call DoXtermButton2    ; Send button2 info
  1469.       mov flag_doButton2,FALSE
  1470.       jmp short @@do_xterm_exit
  1471. @@do_xterm2:
  1472.       cmp flag_doButton3,TRUE
  1473.         jne short @@do_xterm3
  1474.       call DoXtermButton3    ; Send button3 info
  1475.       mov flag_doButton3,FALSE
  1476.       jmp short @@do_xterm_exit
  1477. @@do_xterm3:
  1478.       mov al,col_target
  1479.       cmp al,col_present
  1480.         jne short @@do_xterma
  1481.       mov al,row_present
  1482.       cmp al,row_target
  1483.         jne short @@do_xterma
  1484.       jmp short @@do_xterm_exit
  1485. @@do_xterma:                    ; We assume the keyboard buffer empty!
  1486.                                 ; Simplifies logic, but may fail.
  1487.       mov ah,col_target         ; AX=Where to report cursor
  1488.       mov al,row_target
  1489.       push ax
  1490.       call StuffLeftButton      ; Stuff Xterm escape into keybuffer
  1491.       pop ax
  1492.       mov col_present,ah
  1493.       mov row_present,al
  1494. @@do_xterm_exit:
  1495.       jmp @@exit
  1496. ;
  1497. @@do_emacs_vi:
  1498.       mov al,row_present
  1499.       cmp row_target,al
  1500.       je short @@downarrow      ; row_target == row_present
  1501. @@arrow_loop:
  1502.       cmp col_present,0
  1503.       je short  @@downarrow     ; col_present == 0
  1504.       call LeftArrow
  1505.       jz short @@arrow_loop_continue  ; it worked
  1506.         jmp @@exit              ; it failed, keybuffer full
  1507. @@arrow_loop_continue:
  1508.       dec col_present           ; move one left
  1509.       jmp @@arrow_loop
  1510. ;
  1511. @@do_matrix:
  1512. @@downarrow:
  1513.       mov al,row_present
  1514.       cmp row_target,al
  1515.       je short @@rightarrow     ;row_target == row_present
  1516.       jl short @@uparrow        ;row_target < row_present
  1517. ;
  1518. ; row_target > row_present
  1519. ;
  1520.       call DownArrow
  1521.       jz short @@down_continue  ; worked
  1522.         jmp @@exit              ; failed, keybuffer full
  1523. @@down_continue:
  1524.       inc row_present           ; move one row down
  1525.       jmp @@downarrow
  1526. ;
  1527. ; row_target < row_present
  1528. ;
  1529. @@uparrow:                      ;row_target < row_present
  1530.       call UpArrow
  1531.       jz short @@up_continue    ; worked
  1532.         jmp @@exit              ; failed, keybuffer full
  1533. @@up_continue:
  1534.       dec row_present           ; move one up
  1535.       jmp @@downarrow
  1536.  
  1537. @@rightarrow:
  1538.       mov al,col_present
  1539.       cmp col_target,al
  1540.       je short @@exit           ; col_target == col_present
  1541.       jl short @@leftarrow      ; col_target < col_present
  1542. ;
  1543. ; col_target > col_present
  1544. ;
  1545.       call RightArrow
  1546.       jz short @@right_continue ; worked
  1547.         jmp @@exit              ; failed, keybuffer full
  1548. @@right_continue:
  1549.       inc col_present           ; move one right
  1550.       jmp @@rightarrow
  1551. ;
  1552. ; col_target < col_present
  1553. ;
  1554. @@leftarrow:
  1555.       call LeftArrow
  1556.       jz short @@left_continue  ; worked
  1557.         jmp @@exit              ; failed, keybuffer full
  1558. @@left_continue:
  1559.       dec col_present           ; move one left
  1560.       jmp @@rightarrow
  1561.  
  1562. @@exit:
  1563.       ret
  1564. StuffArrows endp
  1565.  
  1566.  
  1567. ;
  1568. ; Get mouse position from handler's last call
  1569. ; OUT: al=row, ah=col
  1570. ; USES: AX
  1571. GetMousePosition proc
  1572.       PUSHR <dx,cx>
  1573.       mov cx,current_X
  1574.       shr cx,1          ; Get target column position in cl
  1575.       shr cx,1
  1576.       shr cx,1
  1577.       mov dx,current_Y
  1578.       shr dx,1          ; Get target row position in dl
  1579.       shr dx,1
  1580.       shr dx,1
  1581.       mov al,dl
  1582.       mov ah,cl
  1583.       POPR <cx,dx>
  1584.       ret
  1585. GetMousePosition endp
  1586. ;
  1587. ; Set cursor position. Later, the keyboard buffer is stuffed by "stuff2keybuffer".
  1588. ; Uses: AX
  1589. set_cursor proc
  1590.       PUSHR <bx,ds>
  1591.       call GetMousePosition  ;al=row, ah=col
  1592.       mov col_target,ah
  1593.       mov row_target,al
  1594.       ; Get current text cursor position from BIOS variable
  1595.       mov ax,40h        ; Segment of DOS bios
  1596.       mov ds,ax
  1597.       mov ah,0
  1598.       mov al,byte ptr [ds:62h]   ;Get current video page number
  1599.       add al,al         ; AL=2*AL
  1600.       add al,50h        ; 50h=cursor position bios data (8 16-bit words)
  1601.       mov bx,ax         ; BX=offset in segment 40h
  1602.       mov ax,[ds:bx]    ;Get cursor position for current page
  1603.       mov row_present,ah
  1604.       mov col_present,al
  1605.       mov lasttime,0
  1606.       mov lasttime+2,0  ; shut off click timing
  1607. @@exit:
  1608.       POPR <ds,bx>      ; PUSHR <bx,ds>
  1609.       ret
  1610. set_cursor endp
  1611.  
  1612.  
  1613. ; NB: The next two variables should be in this order before pastebuf
  1614. ; so that /U can de-install the TSR.
  1615.  
  1616. XPC_pspadr dw 0                         ; psp address of installed XPC-mouse
  1617. ENDPAIR dw offset lastpair              ; Pointer to actual end
  1618. BUFLEN  dw BUFFERLEN                    ; Buffer size in bytes
  1619.  
  1620. ; buffer for read characters,
  1621. ; can overwrite initialisation code
  1622.  
  1623. pastebuf equ $
  1624.  
  1625. DE_INSTALL    equ 2     ; See option /U, procedure "get_opt" below.
  1626. REACTIVATE    equ 3     ; See option /R
  1627. NOT_INSTALLED equ 40h   ; FLAG for driver not installed.
  1628. ALL_OK        equ 41h   ; FLAG for all go.
  1629. WRO_VEC       equ 42h   ; FLAG for wrong vector detected.
  1630. MOUSE_FN      equ 80h   ; new function of int 16h that detects
  1631.                         ; previous installation of the program
  1632. INST_HND      equ 67h   ; tell int 16 to reinstall mouse handler
  1633. IDENTCODE     equ 16879 ; A 16-bit number used to test validity of /U
  1634.                         ; and /R options.
  1635.  
  1636.  TESTCPU macro
  1637. ; Test for 80188 cpu or later. See startup code. Not used for XT.
  1638. if not XT
  1639.       mov cl,33       ; Test for 80188 or successor
  1640.       shl ax,cl
  1641.       or  cl,cl       ; 188+ maximally shift 32 positions
  1642.       mov dx,offset wro_cpu_str
  1643.       jz @@errexit
  1644. endif ; not XT
  1645.  endm
  1646.  
  1647.  TESTBIOS macro
  1648. if not XT
  1649. ; Test for modern Bios with int 16,5. See startup code. Not used for XT.
  1650. ; Equipment check for enhanced keyboard.
  1651.       mov ax,40h
  1652.       mov es,ax
  1653.       test byte ptr [es:96h],10000b ; enhanced keyboard installed ?
  1654.       jz @@errexit
  1655. endif ; not XT
  1656.  endm
  1657.  
  1658. ; Local variables used to parse command line. These get wiped out by
  1659. ; the paste buffer, which writes over this area.
  1660. ;
  1661. quiet_flag db FALSE          ; TRUE to display everything, FALSE defeats
  1662. copying_flag db FALSE        ; TRUE to display copying info
  1663. counter_Xoption db 0         ; Counter for number of /M and /X options.
  1664. how_to_flag db FALSE         ; TRUE if to display only How-To string
  1665.  
  1666. ; change interrupts and install mouse handler
  1667. ;
  1668. ; GET OPTIONS. Returns special options in ah.
  1669. ;
  1670. get_opt proc
  1671.         mov si,80h            ; si => command line parameters
  1672.         seges
  1673.         lodsb                 ; count
  1674.         mov bh,0
  1675.         mov bl,al
  1676.         mov es:[si+bx],bh        ; 0
  1677.         or  al,al
  1678.         jnz  @@findslash
  1679.         jmp  @@parm_done
  1680. @@findslash:
  1681.         seges
  1682.         lodsb
  1683.         or al,al
  1684.         jz  @@parm_done
  1685.         cmp al," "
  1686.         jz short @@findslash     ; +DEC CX
  1687.         cmp al,"/"
  1688.         jz  short @@good_sep
  1689.         cmp al,"-"
  1690.         jnz @@parm_err
  1691. @@good_sep:
  1692. ;  Valid options to return in register ah:
  1693. ;  DE_INSTALL, REACTIVATE
  1694. ;
  1695. @@loop:                       ; Added some documentation of steps
  1696.         seges                 ; on 1-Nov-1994
  1697.         lodsb
  1698. @@HELP_setup:
  1699.         cmp al,'?'            ; Got ? on command line
  1700.           jz short @@parm_err
  1701.  
  1702.         and al,not ('a'-'A')  ; toupper
  1703.  
  1704.         cmp al,'H'            ; Got /H on command line
  1705.           jnz @@HELP_setup_exit
  1706.           mov how_to_flag,TRUE
  1707.           jz short @@parm_err
  1708. @@HELP_setup_exit:
  1709. @@U_setup:
  1710.         cmp al,'U'            ; Got /U for uninstall
  1711.         mov ah,DE_INSTALL
  1712.           jnz short @@U_setup_exit
  1713.         jmp @@exit
  1714. @@U_setup_exit:
  1715. @@R_setup:
  1716.         cmp al,'R'            ; Got /R for reactivate driver
  1717.         mov ah,REACTIVATE
  1718.           jnz short @@R_setup_exit
  1719.         jmp @@exit
  1720. @@R_setup_exit:
  1721. ;
  1722. ; Loop on the other command line options
  1723. ;
  1724. @@C_setup:
  1725.         cmp al,'C'            ; Got /C, display copying info
  1726.         jne short @@C_setup_exit
  1727.         mov copying_flag,1
  1728.         jmp @@findslash
  1729. @@C_setup_exit:
  1730. @@P_setup:
  1731.         cmp al,'P'            ; Got /P, defeat pastebuffer
  1732.         jne short @@P_setup_exit
  1733.         mov flag_pastebuffer,0
  1734.         jmp @@findslash
  1735. @@P_setup_exit:
  1736.  
  1737. @@K_setup:
  1738.         cmp al,'K'            ; Got /K, defeat arrow keys
  1739.           jne short @@K_setup_exit
  1740.         mov flag_arrowkeys,0
  1741.         jmp @@findslash
  1742. @@K_setup_exit:
  1743. @@A_setup:
  1744.         cmp al,'A'            ; Got /A, set emacs, matrix, xterm modes
  1745.         jnz short @@A_setup_exit
  1746.         call parse_num        ; Get number nnn after '/A'
  1747.         cmp ax,MAX_of_A       ; Valid options are 1,2,...,(MAX_of_A)-1
  1748.         jae short @@A_setup1
  1749.         cmp ax,1
  1750.         jb short @@A_setup1
  1751.         mov flag_editor,al
  1752. @@A_setup1:
  1753.         jmp @@findslash
  1754. @@A_setup_exit:
  1755.  
  1756. @@N_setup:
  1757.         cmp al,'N'            ; Got /N for no mouse handler saving
  1758.           jnz short @@N_setup_exit
  1759.         mov cs:flag_int21,TRUE
  1760.         jmp @@findslash
  1761. @@parm_err:
  1762.         mov ah,FALSE
  1763.         jmp @@exit
  1764. @@parm_done:
  1765.         mov ah,TRUE
  1766.         jmp @@exit
  1767. @@N_setup_exit:
  1768. @@Q_setup:
  1769.         cmp al,'Q'            ; Got /Q for quiet startup mode
  1770.         jnz short @@Q_setup_exit
  1771.         mov cs:quiet_flag,TRUE
  1772.         jmp @@findslash
  1773. @@Q_setup_exit:
  1774. @@M_setup:
  1775.         cmp al,'M'            ; Got /M for monochrome video mode
  1776.           jnz short @@M_setup_exit
  1777.         mov al,119            ; XOR byte mask for monochrome == /X119
  1778.         jmp short @@X_setup1
  1779. @@M_setup_exit:
  1780. @@X_setup:
  1781.         cmp al,'X'            ; Got /X for XOR mask ddd
  1782.         jnz short @@X_setup_exit
  1783.         call parse_num        ; Get number nnn after '/X'
  1784.         cmp ax,255            ; Value ddd==119 for monochrome
  1785.         ja @@parm_err
  1786.         cmp ax,0
  1787.         jb short @@parm_err
  1788. @@X_setup1:
  1789.         mov xor_mask,al
  1790.         inc counter_Xoption
  1791.         jmp @@findslash
  1792. @@X_setup_exit:
  1793. @@B_setup:
  1794.         cmp al,'B'            ; Got /B for new buffer size in paragraphs
  1795.         jnz short @@B_setup1_exit
  1796.         call parse_num        ; Get number nnn after '/B'
  1797.         cmp ax,BUFFERLEN/16   ; Don't let it get bigger than BUFFERLEN
  1798.         ja @@parm_err         ; But ZERO is OK!
  1799.         shl ax,1              ; Times 2
  1800.         shl ax,1              ; Times 4
  1801.         shl ax,1              ; Times 8
  1802.         shl ax,1              ; Times 16
  1803.         mov cs:BUFLEN,ax
  1804.         jmp @@findslash
  1805. @@B_setup1_exit:
  1806. @@T_setup:
  1807.         cmp al,'T'            ; Got /T for for Timer interrupt option
  1808.         jne @@T_setup_exit
  1809.         mov cs:flag_int1c,TRUE ;Enable timer click code int 1ch
  1810.         jmp @@findslash
  1811. @@T_setup_exit:
  1812.         jmp @@findslash
  1813. @@exit:
  1814.         ret
  1815. get_opt endp
  1816.  
  1817.  
  1818. parse_num proc
  1819.         mov bx,10
  1820.         mov ax,0
  1821.         mov dh,0
  1822. @@addloop:
  1823.         seges
  1824.         mov dl,[si]
  1825.         or dl,dl
  1826.         jz  short @@done
  1827.         inc si
  1828.         sub dl,'0'
  1829.         jc short @@done
  1830.         cmp dl,9
  1831.         ja short @@done
  1832.         push dx
  1833.         mul bx
  1834.         pop dx
  1835.         add ax,dx
  1836.         jmp short @@addloop
  1837. @@done:
  1838.         ret
  1839. parse_num endp
  1840.  
  1841. inst_tst proc   ; exit: Z = installed
  1842.         PUSHR <ax,dx,cx>
  1843.         mov ah,MOUSE_FN        ; test for installed, call patched int16h
  1844.         mov al,MOUSE_FN
  1845.         push ax
  1846.         int 16h                ; es:bx points to pastebuf
  1847.         pop dx
  1848.         dec dh
  1849.         cmp ah,dh
  1850.         jnz short @@exit
  1851.         cmp cx,IDENTCODE
  1852. @@exit:
  1853.         POPR <cx,dx,ax>
  1854.         ret
  1855. inst_tst endp
  1856.  
  1857. cmp_fptr proc ; cmp ax:bx and cx:dx
  1858.         XPUSHA
  1859.         mov si,0
  1860.         mov di,0
  1861.  
  1862. ; si:ax *= 16
  1863.         rept 4
  1864.           shl ax,1
  1865.           rcl si,1
  1866.         endm
  1867.         add ax,bx
  1868.         adc si,0
  1869.  
  1870. ; di:cx *= 16
  1871.         rept 4
  1872.           shl cx,1
  1873.           rcl di,1
  1874.         endm
  1875.         add cx,dx
  1876.         adc di,0
  1877.  
  1878.         cmp cx,ax
  1879.         jnz short @@exit
  1880.         cmp si,di
  1881. @@exit:
  1882.         XPOPA
  1883.         ret
  1884. cmp_fptr endp
  1885.  
  1886.       ms_hnd_ptr dw 0,0
  1887.  
  1888. re_activate proc
  1889. LOCAL  hndadr:DWORD = AUTO_SIZE
  1890.        push bp
  1891.        mov  bp,sp
  1892.        sub  sp,AUTO_SIZE
  1893.       PUSHR <ds,es>
  1894.       call inst_tst
  1895.       mov al,NOT_INSTALLED
  1896.       jnz short @@exit
  1897.  
  1898.       mov ah,MOUSE_FN ; far address of pastebuf is in registers es:bx
  1899.       mov al,MOUSE_FN
  1900.       int 16h
  1901.       ; Load bx with pointer to proc InstallMouseHandler
  1902.       sub bx,pastebuf-InstallMouseHandler
  1903.       mov word ptr hndadr,bx
  1904.       mov bx,es
  1905.       mov word ptr hndadr+2,bx
  1906.       call dword ptr [hndadr]
  1907.  
  1908. @@exit:
  1909.       POPR <es,ds>
  1910.        add  sp,AUTO_SIZE
  1911.        pop bp
  1912.       ret
  1913. re_activate endp
  1914.  
  1915. RSTVEC macro vec,old_vec_dist
  1916.       mov bx,pcmoffs
  1917.       sub bx,old_vec_dist
  1918.       lds dx,[es:bx]
  1919.       mov ax,(25h shl 8) + vec           ; set vector
  1920.       int 21h
  1921. endm
  1922.  
  1923. CMPVEC macro vec,new_vec_dist
  1924.       mov ax,(35h shl 8) + vec           ; get vector
  1925.       int 21h                            ; to es:bx
  1926.  
  1927.       mov ax,es
  1928.       mov cx,pcmseg
  1929.       mov dx,pcmoffs
  1930.       sub dx,new_vec_dist
  1931.       call cmp_fptr      ; cmp ax:bx and cx:dx
  1932.       jnz @@wrong_vec
  1933. endm
  1934.  
  1935. de_inst proc
  1936. LOCAL  pcmoffs,pcmseg:WORD,safeflg:BYTE,tckflg:BYTE = AUTO_SIZE
  1937.        push bp
  1938.        mov  bp,sp
  1939.        sub  sp,AUTO_SIZE
  1940.        PUSHR <ds,es>
  1941.       call inst_tst
  1942.       mov al,NOT_INSTALLED
  1943.         jz short @@cont_de_inst
  1944.       jmp @@goexit
  1945. @@cont_de_inst:
  1946. ; now test for all patched vectors, if they point to xpcmouse
  1947.       mov ah,MOUSE_FN ; far address pastebuf returned
  1948.       mov al,MOUSE_FN ; in registers es:bx
  1949.       int 16h
  1950.       mov pcmoffs,bx  ; Offset to pastebuf
  1951.       mov ax,es
  1952.       mov pcmseg,ax   ; Segment of installed xpc-mouse
  1953.       push bx
  1954.       sub bx,pastebuf-flag_int1c
  1955.       mov al,es:[bx]
  1956.       mov tckflg,al    ; use flag_int1c of installed copy
  1957.       pop bx
  1958.  
  1959.       sub bx,pastebuf-flag_int21
  1960.       mov al,es:[bx]
  1961.       mov safeflg,al   ; use flag_int21 of installed copy
  1962.  
  1963.      cmp safeflg,TRUE
  1964.         jz short @@no_21_test
  1965.       CMPVEC 21h,pastebuf-new_21h
  1966.  
  1967. @@no_21_test:
  1968.       CMPVEC 16h,pastebuf-new_16h
  1969.       CMPVEC 10h,pastebuf-new_10h
  1970.  
  1971.       cmp tckflg,TRUE
  1972.         jnz short @@de_inst
  1973.       CMPVEC 1ch,pastebuf-new_1ch
  1974.         jmp short @@de_inst
  1975.  
  1976. @@wrong_vec:
  1977.         mov al,WRO_VEC
  1978. @@goexit:
  1979.         jmp short @@exit
  1980.  
  1981. @@de_inst:
  1982.  
  1983.      cmp safeflg,TRUE
  1984.         jz short @@no_21_deinst
  1985.         RSTVEC 21h,pastebuf-old_21h
  1986.  
  1987. @@no_21_deinst:
  1988.         RSTVEC 16h,pastebuf-old_16h
  1989.         RSTVEC 10h,pastebuf-old_10h
  1990.  
  1991.       cmp tckflg,TRUE
  1992.         jnz short @@no_tick2
  1993.         RSTVEC 1ch,pastebuf-old_1ch
  1994. @@no_tick2:
  1995.  
  1996. ; reset driver is done at end of last exec, too
  1997.         mov ax,0h
  1998.         int 33h     ; reset mouse driver & HW & interrupt handler
  1999.  
  2000.         mov es,pcmseg              ; segment of installed xpc-mouse
  2001.         mov bx,pcmoffs             ; offset into that segment
  2002.         sub bx,pastebuf-killed_flg ; get offset to killed_flg in "new_21h"
  2003.         mov byte ptr [es:bx],TRUE  ; Prevent re-entry of "new_21h"
  2004.         mov bx,pcmoffs             ; offset to pastebuf
  2005.         sub bx,pastebuf-XPC_pspadr ; offset to storage word
  2006.         mov es,[es:bx]             ; Get psp address word
  2007.         mov ah,49h ; free memory
  2008.         int 21h
  2009.  
  2010.         mov al,ALL_OK
  2011.         jmp @@exit
  2012.  
  2013. @@exit:
  2014.        POPR <es,ds>
  2015.        add  sp,AUTO_SIZE
  2016.        pop bp
  2017.        ret
  2018. de_inst endp
  2019.  
  2020. init proc
  2021.       mov ax,es
  2022.       mov cs:XPC_pspadr,ax      ; Save a copy in resident code
  2023.       mov ax,cs
  2024.       mov ds,ax
  2025.       call get_opt
  2026.       push ax
  2027.  
  2028. ; Output copying message and quit?
  2029.       cmp cs:copying_flag,FALSE
  2030.         jz short @@no_copying
  2031.       pop ax
  2032.       mov dx,offset copying
  2033.       jmp @@do_exit
  2034.  
  2035. @@no_copying:
  2036.       cmp cs:quiet_flag,TRUE
  2037.       jz short @@no_onsign
  2038.       mov dx,offset onsign
  2039.       mov ah,9
  2040.       int 21h
  2041.  
  2042. @@no_onsign:
  2043.       pop ax
  2044.       cmp cs:how_to_flag,TRUE
  2045.         jnz short @@no_onsign1
  2046.         jz @@do_howto_exit
  2047. @@no_onsign1:
  2048.       cmp ah,TRUE
  2049.         jz short @@cont_inst
  2050.       cmp ah,FALSE
  2051.         mov dx,offset help_str
  2052.         jz @@do_exit
  2053.       cmp ah,REACTIVATE
  2054.         jnz short @@tst_de_inst
  2055.       call re_activate
  2056.         cmp al,NOT_INSTALLED
  2057.         jz short @@not_yet1
  2058.         mov dx,offset re_inst_str
  2059.          jmp @@do_exit
  2060.  
  2061. @@tst_de_inst:
  2062.       cmp ah,DE_INSTALL
  2063.         jnz short @@cont_inst
  2064.       call de_inst
  2065.         cmp al,NOT_INSTALLED
  2066. @@not_yet1:
  2067.         mov dx,offset not_yet_str
  2068.          jz @@do_exit
  2069.         cmp al,ALL_OK
  2070.         mov dx,offset ok_de_inst
  2071.          jz @@do_exit
  2072.         mov dx,offset wro_de_inst
  2073.          jmp @@do_exit
  2074.  
  2075. @@cont_inst:
  2076.  
  2077.       TESTCPU         ; Test for 80188 cpu or later. See macro above.
  2078.       TESTBIOS        ; Test for modern bios. See macro above.
  2079.  
  2080. ; use function 21h (instead of 0) to ensure that new
  2081. ; mouse driver is installed
  2082.  
  2083.       mov ax,21h             ; Test, if mouse driver installed
  2084.       int 33h
  2085.       inc ax                 ; installed => 0
  2086.         jz short @@mouse_there
  2087.  
  2088.       mov dx,offset nomouse_str
  2089. @@errexit:
  2090.       mov ah,9
  2091.       int 21h
  2092.       mov  dx,offset noins_str
  2093. @@do_exit:
  2094.       mov  ah,9
  2095.       int  21h
  2096.       mov  ax,4c01h          ; errorlevel 1 == no mouse driver
  2097.       int  21h
  2098.  
  2099. @@mouse_there:
  2100.       call inst_tst
  2101.       jnz short @@install
  2102.  
  2103. @@do_howto_exit:
  2104.       mov dx,offset help_switches
  2105.       mov  ah,9
  2106.       int  21h
  2107.  
  2108.       mov dx,offset how_to
  2109.       mov ah,9
  2110.       int 21h
  2111.  
  2112.       cmp cs:how_to_flag,FALSE
  2113.         je @@exit02
  2114.       mov  ax,4c03h          ; errorlevel 3 == message exit
  2115.       int  21h
  2116.  
  2117. @@exit02:
  2118.       mov dx,offset msgstr
  2119.       mov ah,9
  2120.       int 21h
  2121.       mov  ax,4c02h          ; errorlevel 2 == re-installed
  2122.       int  21h
  2123.  
  2124. @@install:
  2125.  
  2126. ; Set buffer length variable
  2127.  
  2128.       mov ax,cs:BUFLEN          ; Get ending address of the
  2129.       add ax,offset pastebuf-1  ; Paste Buffer
  2130.       mov cs:EndOfBuffer,ax     ; and save it
  2131.  
  2132. ; See if the video mode is appropriate for the /Xddd mask
  2133.       cmp cs:counter_Xoption,0  ; Over-ride on command line?
  2134.         jnz short @@video_OK
  2135.       ;   Option /M for monochrome Video mode (/M==/X119).
  2136.       push ds
  2137.       mov ax,40h                ; Segment of bios
  2138.       mov ds,ax
  2139.       cmp byte ptr [ds:49h],7   ; BIOS current video mode mono?
  2140.       pop ds
  2141.         jnz short @@video_OK
  2142.       mov xor_mask,119          ; Use /X119 for mono
  2143. @@video_OK:
  2144.  
  2145. ; free environment
  2146. ; Space managed by DOS can be re-used.
  2147. ;
  2148.       mov es,cs:XPC_pspadr
  2149.       mov es,[es:2ch]   ; segment address of environment
  2150.       mov ah,49h        ; free memory
  2151.       int 21h
  2152.  
  2153.       mov ax,3516h
  2154.       int 21h           ; get vector
  2155.       mov word ptr old_16h,bx
  2156.       mov word ptr cs:[old_16h+2],es
  2157.  
  2158.       mov ax,351ch
  2159.       int 21h                ; get vector
  2160.       mov word ptr old_1ch,bx
  2161.       mov word ptr cs:[old_1ch+2],es
  2162.  
  2163.       mov ax,3510h
  2164.       int 21h
  2165.       mov word ptr cs:[old_10h],bx
  2166.       mov word ptr cs:[old_10h+2],es
  2167.  
  2168. ; with option /N don't install int 21h patch
  2169.  
  2170.      cmp cs:flag_int21,TRUE
  2171.         jz short @@no_21_inst
  2172.       mov ax,3521h
  2173.       int 21h
  2174.       mov word ptr cs:[old_21h],bx
  2175.       mov word ptr cs:[old_21h+2],es
  2176.       mov dx,offset new_21h
  2177.       mov ax,2521h           ; set vect
  2178.       int 21h
  2179.  
  2180. @@no_21_inst:
  2181.       mov dx,offset new_10h
  2182.       mov ax,2510h           ; set vect
  2183.       int 21h
  2184.       mov dx,offset new_16h
  2185.       mov ax,2516h           ; set vect
  2186.       int 21h
  2187.  
  2188.       cmp cs:flag_int1c,FALSE
  2189.         jz short @@no_tick_set
  2190.       mov dx,offset new_1ch
  2191.       mov ax,251ch           ; set vect
  2192.       int 21h
  2193. @@no_tick_set:
  2194.  
  2195.       call InstallMouseHandler
  2196.  
  2197.       cmp cs:quiet_flag,TRUE
  2198.         jz short @@terminate
  2199.       mov dx,offset how_to
  2200.       mov ah,9
  2201.       int 21h
  2202.       mov dx,offset worked
  2203.       mov ah,9
  2204.       int 21h
  2205.  
  2206. @@terminate:
  2207.       ; Compute how many paragraphs are to be resident.
  2208.       ; This count adds is code length plus paste buffer length. The
  2209.       ; paste buffer has by design a maximum length of BUFFERLEN bytes.
  2210.       ;
  2211.       mov dx,cs:BUFLEN          ; Desired buffer length
  2212.       add dx,offset pastebuf    ; resident code len + BUFLEN
  2213.       add dx,15+256             ; Roundup + EXE header size
  2214.       shr dx,1                  ; dx --> (end_mouse - begin_resident+15+256)/2
  2215.       shr dx,1                  ; dx --> (end_mouse - begin_resident+15+256)/4
  2216.       shr dx,1                  ; dx --> (end_mouse - begin_resident+15+256)/8
  2217.       shr dx,1                  ; dx --> (end_mouse - begin_resident+15+256)/16
  2218.       mov ax,3100h
  2219.       int 21h                ; terminate stay resident
  2220.  
  2221. init endp
  2222.  
  2223. copying:
  2224.        db 'Copyright (c) 1994 Jürgen G. Weber and G.B. Gustafson',13,10
  2225.        db 'xPC-Mouse is free software, distributed under the terms of the',13,10
  2226.        db 'GNU General Public License. For details, see the file COPYING.',13,10
  2227.        db 10
  2228.        db 'Jürgen G. Weber',13,10
  2229.        db 'Wiesentalstraße 1',13,10
  2230.        db 'D-74523 Schwäbisch Hall',13,10
  2231.        db 'Germany',13,10
  2232.        db 'email: weberj@dia.informatik.uni-stuttgart.de',13,10
  2233.        db 10
  2234.        db 'Grant B. Gustafson',13,10
  2235.        db '113 JWB Math Dept Univ Utah',13,10
  2236.        db 'Salt Lake City, UT 84112  USA',13,10
  2237.        db 'email: gustafson@math.utah.edu',13,10
  2238.        db '$'
  2239.  
  2240. onsign db 13,10,'xPC-Mouse, version ',PVERSION,13,10
  2241.        db 'Copyright (c) 1994 Jürgen G. Weber and G.B. Gustafson',13,10
  2242.        db 'Free for personal use under the Gnu license agreement.',13,10
  2243.        db 10,'$'
  2244.  
  2245. how_to:
  2246.        db 'MOUSE BUTTON             FUNCTION',13,10
  2247.        db 'Mouse 1 (1/6 second) ... Position cursor',13,10
  2248.        db 'Mouse 2 ................ Paste text',13,10
  2249.        db 'Drag Mouse 1 ........... Copy text',13,10
  2250.        db 'Double-click Mouse 1 ... Copy word',13,10
  2251.        db 'CTRL-Mouse 2 ........... Paste text + ENTER',13,10
  2252.        db 'ALT-Mouse 2 ............ Mouse 3 duplicate',13,10
  2253.        db 'SHIFT-Mouse 1 .......... Cursor feature on/off ',13,10
  2254.        db 'SHIFT-ALT-Mouse 1 ...... Toggle methods /A1-/A3',13,10
  2255.        db 'SHIFT-Mouse 2 .......... Paste feature on/off',13,10
  2256.        db '$'
  2257.  
  2258. worked db 13,10
  2259.        db 'xPC-Mouse is installed. Use "xPCmouse /U" to un-install.',13,10,'$'
  2260. msgstr db 13,10
  2261.        db 'xPC-Mouse was already installed.',13,10,'$'
  2262. not_yet_str db 13,10,  'xPC-Mouse was not installed yet.',13,10,'$'
  2263. ok_de_inst  db 13,10,  'xPC-Mouse is un-installed.',13,10,'$'
  2264. re_inst_str db 13,10,  'xPC-Mouse is re-activated.',13,10,'$'
  2265. wro_de_inst db 13,10,  'Could not un-install xPC-Mouse.',13,10,'$'
  2266. nomouse_str db 13,10,7,'No mouse driver found or driver too old.',13,10,'$'
  2267. noins_str   db         'xPC-Mouse not installed.',13,10,'$'
  2268. wro_cpu_str db         'xPC-Mouse needs at least an 80286 with',13,10
  2269.             db         'extended keyboard support.',13,10,'$'
  2270. help_str db 13,10,'Options: /U    : Un-install xPC-Mouse',13,10
  2271.                db '         /Q    : Quiet, no messages',13,10
  2272.                db '         /R    : Re-activate xPC-Mouse',13,10
  2273.                db '         /M    : Monochrome video mode (equals /X119)',13,10
  2274.                db '         /Xddd : Highlight XOR mask ddd (default /X80)',13,10
  2275.                db '         /Bddd : Buffer size ddd paragraphs (16*ddd bytes)',13,10
  2276.                db '         /T    : Enable timer int 1Ch patch',13,10
  2277.                db '         /N    : Defeat int 21h patch',13,10
  2278.                db '         /P    : Defeat pastebuffer use',13,10
  2279.                db '         /K    : Defeat arrow key emulation',13,10
  2280.                db '         /A1   : Emacs/vi arrow key method (default)',13,10
  2281.                db '         /A2   : Matrix arrow key method',13,10
  2282.                db '         /A3   : Xterm escape sequence method',13,10
  2283. help_switches:
  2284.                db 'Info:    /C    : Display copying information',13,10
  2285.                db '         /?    : Display help text',13,10
  2286.                db '         /H    : Display mouse button assigments',13,10
  2287.          db 13,10,'$'
  2288.  
  2289. ; Insure source file is long enough when loaded into memory
  2290. ; so that the pastebuffer is the proper size.
  2291. ;
  2292. if  ($-pastebuf) lt BUFFERLEN
  2293.         db  BUFFERLEN-($-pastebuf) dup (?)
  2294. endif
  2295.  
  2296. end_mouse equ pastebuf+BUFFERLEN
  2297. code ends
  2298.  
  2299. ; Stack segment is only used during initialization
  2300.  
  2301. stck segment para stack 'stack'
  2302.   db 256 dup (?)
  2303. stck ends
  2304.  
  2305. end init
  2306.  
  2307. comment *
  2308. GNU PUBLIC LICENSE.
  2309.    This software is released as copyrighted material under the GNU PUBLIC
  2310.    LICENSE:
  2311.  
  2312.                            NO WARRANTY
  2313.  
  2314.    Because xPC-Mouse is licensed free of charge, absolutely no warranty
  2315.    is provided, to the extent permitted by applicable state law.  Except
  2316.    when otherwise stated in writing, Jürgen G. Weber and Grant B.
  2317.    Gustafson provides xPC-Mouse "as is" without warranty of any kind,
  2318.    either expressed or implied, including, but not limited to, the
  2319.    implied warranties of merchantability and fitness for a particular
  2320.    purpose. The entire risk as to the quality and performance of the
  2321.    program is with you. Should the xPC-Mouse program prove defective,
  2322.    you assume the cost of all necessary servicing, repair or correction.
  2323.  
  2324.    In no event unless required by applicable law will Grant B. Gustafson
  2325.    and Jürgen G. Weber and/or any other party who may modify and
  2326.    redistribute xPC-Mouse be liable to you for damages, including any
  2327.    lost profits, lost monies, or other special, incidental or
  2328.    consequential damages arising out of the use or inability to use
  2329.    (including but not limited to loss of data or data being rendered
  2330.    inaccurate or losses sustained by third parties or a failure of the
  2331.    program to operate with programs not distributed by Grant B.
  2332.    Gustafson and Jürgen G. Weber) the program, even if you have been
  2333.    advised of the possibility of such damages, or for any claim by any
  2334.    other party.
  2335.  
  2336. NO COST?
  2337.    This software is provided free of charge to individuals and educational
  2338.    institutions. Money is not requested.
  2339.  
  2340. POSTCARDS?
  2341.    Postcards and comments are welcome!
  2342.  
  2343.    Jürgen G. Weber               GB Gustafson
  2344.    Wiesentalstraße 1             113 JWB Math Dept Univ Utah
  2345.    D-74523 Schwäbisch Hall       Salt Lake City, UT 84112
  2346.    Germany - European Union      USA
  2347.  
  2348. * ; End comment
  2349.